﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Text.RegularExpressions;
using System.IO;
using FrtSvrGPRS;
using AllData;

namespace SerialportSample
{
    public partial class SerialportSampleForm : Form
    {
        public SerialPort comm = new SerialPort();
        private static string path = Environment.CurrentDirectory;   ///////////当前程序的运行路径
        public static bool is_run = false;
        private StringBuilder builder = new StringBuilder();//避免在事件处理方法中反复的创建，定义到外面。
        public bool is_pl=false;
        public bool k_h = false;  ///
        public bool is_cs = false;
        public static string[] comp;   /// <summary>
        public static int addr = 0;
        public static bool is_flash = true; /////是否滚动报文
        public static cs_cls[] cs_list;    /// 系统遥信点表
        public static int st = 0;
        public static int end = 0;

        /// /保存测试的名称
        /// </summary>
        public SerialportSampleForm()
        {
            InitializeComponent();
        }

        //窗体初始化
        private void Form1_Load(object sender, EventArgs e)
        {
            //初始化下拉串口名称列表框

            int ty = 0;
            string[] ports = SerialPort.GetPortNames();
            Array.Sort(ports);
            comboPortName.Items.AddRange(ports);
            comboPortName.SelectedIndex = comboPortName.Items.Count > 0 ? 0 : -1;
            comboBaudrate.SelectedIndex = comboBaudrate.Items.IndexOf("115200");
            //向校验位下拉框里添加检错方式，NONE，ODD，EVEN
            comboParity.Items.Add("NONE");
            comboParity.Items.Add("ODD");
            comboParity.Items.Add("EVEN");

            //初始化SerialPort对象
            comm.NewLine = "\r\n";
            comm.RtsEnable = true;
            ///////////////////加载INI文件
            string file = path + "\\xiaoq.ini";
            IniFile ini = new IniFile(file);
            comboParity.Text= ini.ReadIni("xiaoq", "part", "NONE").ToString();
            comboBaudrate.Text = ini.ReadIni("xiaoq", "boud", "115200").ToString();
            comboPortName.SelectedIndex = Convert.ToInt16(ini.ReadIni("xiaoq", "com", "0").ToString());
            //添加事件注册
            comm.DataReceived += comm_DataReceived;

            com_st.SelectedIndex = -1;
            com_end.SelectedIndex = -1;
            for (int i = 1; i < 100; i++)
            {
                com_st.Items.Add(i.ToString());
                com_end.Items.Add(i.ToString());
            }
            com_st.Text = ini.ReadIni("xiaoq", "start", "1").ToString();
            com_end.Text = ini.ReadIni("xiaoq", "end", "6").ToString();
            jcq.Text = ini.ReadIni("xiaoq", "jcq", "1").ToString();
            ty =Convert.ToInt16(ini.ReadIni("xiaoq", "type", "1").ToString());
            string dat = ini.ReadIni("comp", "type", "通用测试").ToString();
            comp = dat.Split('@');
            for (int i = 0; i < comp.Length; i=i+2)
            {
                com_type.Items.Add(comp[i]);
            }
            com_type.Text = comp[ty * 2];
            timer1.Interval = Convert.ToInt16(ini.ReadIni("xiaoq", "span", "1500").ToString());
            com_tim.Text = ini.ReadIni("xiaoq", "span", "1500").ToString();
            timer1.Enabled = false;
            is_run = false;
            this.Top = 100;
        }

        void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int n = comm.BytesToRead;//先记录下来，避免某种原因，人为的原因，操作几次之间时间长，缓存不一致
            int hs = 0;
            byte[] data = new byte[n];//声明一个临时数组存储当前来的串口数据
            comm.Read(data, 0, n);//读取缓冲数据
            builder.Remove(0, builder.Length);//清除字符串构造器的内容
            try
            {
                //因为要访问ui资源，所以需要使用invoke方式同步ui。
                this.Invoke((EventHandler)(delegate
                {
                    //依次的拼接出16进制字符串
                    foreach (byte b in data)
                    {
                        builder.Append(b.ToString("X2") + " ");
                    }

                    #region 保持100条记录
                    if (baow.Rows.Count > 100)
                    {
                        for (int i = 100; i < baow.Rows.Count; i++)
                        {
                            baow.Rows.RemoveAt(baow.Rows.Count - i);
                        }
                    }
                    #endregion

                    if (is_flash == true)
                    {
                        if (cs_list[data[0] - st].rec == 0)
                        {
                            cs_list[data[0] - st].send = 1;  ////首次接收到数据
                        }
                        cs_list[data[0] - st].rec++;
                        hs = baow.Rows.Add(DateTime.Now.ToString("HH:mm:ss"), "大数据中心", "modbus", "接收" + "[" + data.Length.ToString() + "]", "地址: " + data[0].ToString() + " ", builder);
                        baow.Rows[hs].DefaultCellStyle.BackColor = Color.PaleGreen;
                    }
                    baow.FirstDisplayedScrollingRowIndex = baow.Rows.Count - 1;   ////滚动条至最下面一条
                }));
            }
            catch { }
        }

        private void buttonOpenClose_Click(object sender, EventArgs e)
        {
            //根据当前串口对象，来判断操作
            if (comm.IsOpen)
            {
                //打开时点击，则关闭串口
                comm.Close();
                label6.ForeColor = Color.Black;//串口关闭后，指示灯变黑
                is_run = false;
                buttonOpenClose.BackColor = Color.Red;
                buttonOpenClose.ForeColor = Color.White;
            }
            else
            {
                buttonOpenClose.BackColor = Color.Green;
                buttonOpenClose.ForeColor = Color.White;
                //关闭时点击，则设置好端口，波特率后打开
                comm.PortName = comboPortName.Text;
                comm.BaudRate = int.Parse(comboBaudrate.Text);

                comm.DataBits = Convert.ToInt32("8");//设置数据位
                comm.StopBits = StopBits.One; //设置停止位
                if (comboParity.SelectedIndex == 0)
                {
                    comm.Parity = Parity.None; //设置校验位                    
                }
                else if (comboParity.SelectedIndex == 1)
                {
                    comm.Parity = Parity.Odd; //设置校验位                    
                }
                else
                {
                    comm.Parity = Parity.Even; //设置校验位
                }
                try
                {
                    comm.Open();
                }
                catch(Exception ex)
                {
                    //捕获到异常信息，创建一个新的comm对象，之前的不能用了。
                    comm = new SerialPort();
                    //现实异常信息给客户。
                    MessageBox.Show(ex.Message);
                }
                string file = path + "\\xiaoq.ini";
                IniFile ini = new IniFile(file);
                ini.WriteIni("xiaoq", "com", comboPortName.SelectedIndex.ToString());
                ini.WriteIni("xiaoq", "boud", comboBaudrate.Text);
                ini.WriteIni("xiaoq", "part", comboParity.Text);
                ini.WriteIni("xiaoq", "jcq", jcq.Text);
                ini.WriteIni("xiaoq", "start", com_st.Text);
                ini.WriteIni("xiaoq", "end", com_end.Text);
                ini.WriteIni("xiaoq", "type", com_type.SelectedIndex.ToString());
                ini.WriteIni("xiaoq", "span", com_tim.Text);
                is_run = true;
                timer1.Enabled = true;
                addr = Convert.ToInt16(com_st.Text);
                st = Convert.ToInt16(com_st.Text);
                end= Convert.ToInt16(com_end.Text);

                cs_list = new cs_cls[end- st+1];
                #region 创建测试集
                for (int i = 0; i < end-st+1; i++)
                {
                    cs_list[i] = new cs_cls();
                    cs_list[i].addr = i+st;
                    cs_list[i].send = 0;
                    cs_list[i].rec = 0;
                }
                #endregion 
            }

            //设置按钮的状态
            buttonOpenClose.Text = comm.IsOpen ? "关闭串口" : "打开串口";

        }

        private void comboPortName_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            try
            {
                if (is_run == true)
                {
                    int wz = Convert.ToInt16(jcq.Text);
                    int hs = 0;
                    StringBuilder bu = new StringBuilder();//避免在事件处理方法中反复的创建，定义到外面
                    byte[] dat = modbus_data(Convert.ToByte(addr), Convert.ToByte(0x03), Convert.ToByte(Convert.ToInt16(wz) >> 8 & 0x00ff), Convert.ToByte(wz), Convert.ToByte((1 >> 8) & 0x00ff), Convert.ToByte(1));
                    for (int b = 0; b < dat.Length; b++)
                    {
                        bu.Append(dat[b].ToString("X2") + " ");
                    }
                    #region 保持100条记录
                    if (baow.Rows.Count > 100)
                    {
                        for (int i = 100; i < baow.Rows.Count; i++)
                        {
                            baow.Rows.RemoveAt(baow.Rows.Count - i);
                        }
                    }
                    #endregion
                    if (is_flash == true)
                    {
                        cs_list[addr - st].send = cs_list[addr - st].send + 1;
                        hs = baow.Rows.Add(DateTime.Now.ToString("HH:mm:ss"), "大数据中心", "modbus", "发送" + "[" + dat.Length.ToString() + "]", "地址: " + addr.ToString() + " ", bu);
                        baow.Rows[hs].DefaultCellStyle.BackColor = Color.White;
                    }
                    if (addr == Convert.ToInt16(com_end.Text))
                    {
                        addr = Convert.ToInt16(com_st.Text);
                    }
                    else
                    {
                        addr++;
                    }
                    baow.FirstDisplayedScrollingRowIndex = baow.Rows.Count - 1;   ////滚动条至最下面一条
                    comm.Write(dat, 0, dat.Length);
                }
            }
            catch { }
        }

        private void dbcs_Click(object sender, EventArgs e)
        {
            if (comm.IsOpen == false)
            {
                state.Text = "串口还没有打开！";
                return;
            }
        }

        private void com_type_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                jcq.Text = comp[com_type.SelectedIndex * 2 + 1];
            }
            catch 
            {
                jcq.Text = comp[1];
            }
        }
        public static byte[] modbus_data(byte add, byte dead, byte start_low, byte start_high, byte end_low, byte end_high)
        {
            byte[] data = { add, dead, start_low, start_high, end_low, end_high, 0x00, 0x00 };
            int xda, xdapoly;
            byte i, j, xdabit;
            xda = 0xFFFF;
            xdapoly = 0xA001;
            for (i = 0; i < data.Length - 2; i++)
            {
                xda ^= data[i];
                for (j = 0; j < 8; j++)
                {
                    xdabit = (byte)(xda & 0x01);
                    xda >>= 1;
                    if (xdabit == 1)
                        xda ^= xdapoly;
                }
            }
            data[6] = (byte)(xda & 0xFF);
            data[7] = (byte)(xda >> 8);
            return data;
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            baow.Rows.Clear();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (is_flash == true)
            {
                dis_bt.Text = "暂停显示";
                is_flash = false;
                timer1.Enabled = false;
            }
            else
            {
                dis_bt.Text = "滚动报文";
                is_flash = true;
                timer1.Enabled = true;
            }
        }

        private void button2_Click_1(object sender, EventArgs e)
        {
            llist_re.Items.Clear();
            list_error.Items.Clear();
            for (int i = 0; i < cs_list.Length; i++)
            {
                cs_list[i].rec = 0;
                cs_list[i].send = 0;
            }
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            llist_re.Items.Clear();
            list_error.Items.Clear();
            if (cs_list == null) return;
            for (int i = 0; i < cs_list.Length; i++)
            {
                if (cs_list[i].rec == 0 || cs_list[i].send == 0)
                {
                    list_error.Items.Add("地址:" + cs_list[i].addr.ToString() + "  发/收:[" + cs_list[i].send.ToString() + "/" + cs_list[i].rec.ToString() + "]  质量:0%");
                }
                else
                {
                    double res = Convert.ToDouble(100 * cs_list[i].rec / cs_list[i].send);
                    if (res > 50)
                    {
                        llist_re.Items.Add("地址:" + cs_list[i].addr.ToString() + "  发/收:[" + cs_list[i].send.ToString() + "/" + cs_list[i].rec.ToString() + "]  质量:" + Math.Round(res, 1).ToString() + "%");
                    }
                    else
                    {
                        list_error.Items.Add("地址:" + cs_list[i].addr.ToString() + "  发/收:[" + cs_list[i].send.ToString() + "/" + cs_list[i].rec.ToString() + "]  质量:" + Math.Round(res, 1).ToString() + "%");
                    }
                }
            }
        }
    }
    public class cs_cls  /////dot表类
    {
        public int addr;     ////地址的序号
        public int send;     ///发送的数量
        public int rec;  ////接收的数量
    }
}
